home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Commun⁄Network / Telnet 2.5.src.ThinkC / source / tools.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-09  |  13.3 KB  |  566 lines  |  [TEXT/MPS ]

  1. /*
  2. *      TOOLS.C
  3. *
  4. ****************************************************************************
  5. *                                                                          *
  6. *      part of:                                                            *
  7. *      TCP/IP kernel for NCSA Telnet                                       *
  8. *      by Tim Krauskopf                                                    *
  9. *                                                                          *
  10. *      National Center for Supercomputing Applications                     *
  11. *      152 Computing Applications Building                                 *
  12. *      605 E. Springfield Ave.                                             *
  13. *      Champaign, IL  61820                                                *
  14. *                                                                          *
  15. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  16. *                                                                          *
  17. ****************************************************************************
  18. *
  19. *  Portions of the driver code that are not specific to a particular protocol
  20. *
  21. */
  22. #include <stdio.h>
  23. #include "protocol.h"
  24. #include "data.h"
  25. #include "mactools.h"
  26. #include "tcp.h"
  27.  
  28. #include <Events.h>
  29. #include <String.h>
  30.  
  31. extern short slip_connection;        /* BYU 2.4.15 */
  32.  
  33. /***************************************************************************/
  34. /*  enqueue
  35. *   add something to a TCP queue.  Used by both 'write()' and tcpinterpret
  36. *   WINDOWSIZE is the size limitation of the advertised window.
  37. */
  38. int enqueue
  39.   (
  40.     struct window *wind,
  41.     char *buffer,
  42.     int nbytes
  43.   )
  44.     {
  45.     int i;
  46.     
  47.     i = WINDOWSIZE - wind->contain;
  48.     if (i <= 0 || nbytes == 0)
  49.         return(0);                        /* no room at the inn */
  50.  
  51.     if (nbytes > i)
  52.         nbytes = i;
  53.  
  54.     i = wind->where - wind->endlim;        /* room at end */
  55.     i += WINDOWSIZE;
  56.  
  57.     if (i < nbytes) {
  58.         movebytes(wind->endlim,buffer,i);
  59.         movebytes(wind->where,(char *)(buffer+i),nbytes-i);
  60.         wind->endlim = wind->where + nbytes - i;
  61.     } 
  62.     else {
  63.         movebytes(wind->endlim,buffer,nbytes);        /* fits in one chunk */
  64.         wind->endlim += nbytes;
  65.     }
  66.     wind->contain += nbytes;            /* more stuff here */
  67.  
  68.     return(nbytes);
  69.  
  70. }
  71.  
  72. /*************************************************************************/
  73. /* dequeue
  74. *     used by read, this copies data out of the queue and then
  75. *  deallocates it from the queue.
  76. *  cpqueue and rmqueue are very similar and are to be used by tcpsend
  77. *  to store unacknowledged data.
  78. *
  79. *  returns number of bytes copied from the queue
  80. */
  81. int dequeue
  82.   (
  83.     struct window *wind,
  84.     char *buffer,
  85.     int nbytes                /* maximum number to copy out */
  86.   )
  87.     {
  88.     int i;
  89.  
  90.     if (wind->contain == 0)
  91.         return(0);
  92.  
  93.     if (wind->contain < nbytes)
  94.         nbytes = wind->contain;
  95.  
  96.     i = wind->endbuf - wind->base;
  97.  
  98.     if (i <= nbytes) {
  99.         memmove(buffer,wind->base,i);                            /* BYU LSC */
  100.         memmove((char *)(buffer+i),wind->where,nbytes-i);        /* BYU LSC */
  101.         wind->base = wind->where + nbytes-i;
  102.     }
  103.     else {
  104.         memmove(buffer, wind->base, nbytes);                    /* BYU LSC */
  105.         if (wind->contain == nbytes) 
  106.             wind->base = wind->endlim = wind->where;
  107.         else
  108.             wind->base += nbytes;
  109.     }
  110.     
  111.     wind->contain -= nbytes;
  112.  
  113.     return(nbytes);
  114.  
  115. }
  116.  
  117. #ifdef notneeded
  118. /**************************************************************************/
  119. /*  cpqueue
  120. *       does the same thing as dequeue, but does not deallocate the data
  121. *   used when transmitting TCP data.  When the data is ACKed, then 
  122. *   rmqueue is called to deallocate the correct amount of data.
  123. */
  124. cpqueue(wind,buffer,nbytes)
  125.     struct window *wind;
  126.     char *buffer;
  127.     int nbytes;                /* maximum number to copy out */
  128.     {
  129.     int i;
  130.  
  131.     if (wind->contain == 0)
  132.         return(0);
  133.  
  134.     if (wind->contain < nbytes)
  135.         nbytes = wind->contain;
  136.  
  137.     i = wind->endbuf - wind->base;
  138.  
  139.     if (i < nbytes) {
  140.         movebytes(buffer,wind->base,i);
  141.         movebytes((char *)(buffer+i),wind->where,nbytes-i);
  142.     }
  143.     else 
  144.         movebytes( buffer, wind->base, nbytes);
  145.     
  146.     return(nbytes);
  147.  
  148. }
  149. #endif
  150.  
  151. /**************************************************************************/
  152. /*  rmqueue
  153. *     does the queue deallocation that is left out of cpqueue
  154. *
  155. *   rmqueue of WINDOWSIZE or greater bytes will empty the queue
  156. */
  157. int rmqueue
  158.   (
  159.     struct window *wind,
  160.     int nbytes                    /* number to remove */
  161.   )
  162.     {
  163.     int i;
  164.  
  165.     if (wind->contain < nbytes)
  166.         nbytes = wind->contain;
  167.  
  168.     i = wind->endbuf - wind->base;
  169.  
  170.     if (i <= nbytes) 
  171.         wind->base = wind->where+nbytes-i;
  172.     else {
  173.         if (wind->contain == nbytes)
  174.             wind->base = wind->endlim = wind->where;
  175.         else
  176.             wind->base += nbytes;
  177.     }
  178.     
  179.     wind->contain -= nbytes;
  180.  
  181.     return(nbytes);
  182.  
  183. }
  184.  
  185.  
  186. /************************************************************************/
  187. /* comparen
  188. *  Take n bytes and return identical (true=1) or not identical (false=0)
  189. *
  190. *  Could be written in assembler for improved performance
  191. */
  192. int comparen
  193.   (
  194.     uint8 *s1,
  195.     uint8 *s2,
  196.     register int n
  197.   )
  198.     {
  199.  
  200.     while (n--)
  201.         if (*s1++ != *s2++)
  202.             return(0);
  203.  
  204.     return(1);
  205.  
  206. }
  207.  
  208. /***********************************************************************/
  209. /*  netgetevent
  210. *   Retrieves the next event (and clears it) which matches bits in
  211. *   the given mask.  Returns the event number or -1 on no event present.
  212. *   Also returns the exact class and the associated integer in reference
  213. *   parameters.
  214. *
  215. *   The way the queue works:
  216. *     There is always a dummy record pointed to by nnelast.
  217. *     When data is put into the queue, it goes into nnelast, then nnelast
  218. *        looks around for another empty one to obtain.
  219. *        It looks at nnefree first, then bumps one from nnefirst if necessary.
  220. *     When data is retrieved, it is searched from nnefirst to nnelast.
  221. *        Any freed record is appended to nnefree.
  222. */
  223. int netgetevent
  224.   (
  225.     uint8 mask,
  226.     int *retclass,
  227.     int *retint
  228.   )
  229.     {
  230.     int i,j;
  231.  
  232.     i = j = nnefirst;
  233.  
  234.     while (i != nnelast) {
  235.         if (mask & nnq[i].eclass) {
  236.             if (i == nnefirst) 
  237.                 nnefirst = nnq[nnefirst].next;        /* step nnefirst */
  238.             else 
  239.                 nnq[j].next = nnq[i].next;            /* bypass record i */
  240.  
  241.             nnq[i].next = nnefree;
  242.             nnefree = i;                            /* install in free list */
  243.             *retint = nnq[i].idata;
  244.             *retclass = nnq[i].eclass;
  245.             return(nnq[i].event);
  246.         }
  247.         j = i;
  248.         i = nnq[i].next;
  249.     }
  250.  
  251.     return(0);
  252.  
  253. }
  254.  
  255. /***********************************************************************/
  256. /*  netputevent
  257. *   add an event to the queue.
  258. *   Will probably get the memory for the entry from the free list.
  259. *   Returns 0 if there was room, 1 if an event was lost.
  260. */
  261. int netputevent
  262.   (
  263.     int class,
  264.     int what,
  265.     int dat
  266.   )
  267.     {
  268.     int i; 
  269.     
  270.     i = nnelast;
  271.     nnq[i].eclass = class;                    /* put data in */
  272.     nnq[i].event = what;
  273.     nnq[i].idata = dat;
  274.  
  275.     if (nnefree >= 0) {                        /* there is a spot in free list */
  276.         nnq[i].next = nnelast = nnefree;
  277.         nnefree = nnq[nnefree].next;        /* remove from free list */
  278.         return(0);
  279.     }
  280.     else {
  281.         nnq[i].next = nnelast = nnefirst;
  282.         nnefirst = nnq[nnefirst].next;        /* lose oldest event */
  283.         return(1);
  284.     }
  285. }
  286.  
  287. /***************************************************************************/
  288. /*  netputuev
  289. *   put a unique event into the queue
  290. *   First searches the queue for like events
  291. */
  292. int netputuev
  293.   (
  294.     int class,
  295.     int what,
  296.     int dat
  297.   )
  298.     {
  299.     int i;
  300.  
  301.     i = nnefirst;
  302.     while (i != nnelast) {
  303.         if (nnq[i].idata == dat && nnq[i].event == what &&
  304.             nnq[i].eclass == class)
  305.             return(0);
  306.         i = nnq[i].next;
  307.     }
  308.  
  309.     return(netputevent(class,what,dat));
  310.  
  311. }
  312.  
  313. /************************************************************************/
  314. /*  netposterr
  315. *   place an error into the event q
  316. *   Takes the error number and puts it into the error structure
  317. */
  318. void netposterr
  319.   (
  320.     int num
  321.   )
  322.   {
  323.  
  324.     if (netputevent(ERRCLASS,ERR1,num))
  325.  
  326.         netputuev(ERRCLASS,ERR1,501);            /* only if we lost an event */
  327.   }
  328.  
  329. /************************************************************************/
  330. /*  transq
  331. *
  332. *   Needed for TCP, not as general as cpqueue, 
  333. *   but is required for efficient uploading
  334. *
  335. *   Transmit the entire queue (window) to the other host without expecting
  336. *   any sort of acknowledgement.
  337. *
  338. */
  339. int transq
  340.   (
  341.     struct port *prt
  342.   )
  343.     {
  344.     uint bites;
  345.     int i,j,n;
  346.     struct window *wind;
  347.     uint32 saveseq;
  348.     uint8 *endb,*whereb,*baseb;
  349.  
  350.     if (prt == NULL) {
  351.         nnerror(406);        /* NULL port for trans */
  352.         return(-1);
  353.     }
  354.  
  355.     wind = &prt->out;
  356. /*
  357. *   find out how many bytes the other side will allow us to send (window)
  358. */
  359.     bites = wind->size;
  360.     if (wind->contain < bites)
  361.         bites = wind->contain;
  362.  
  363. /*
  364. *  set up the tcp packet for this, ACK field is same for all packets
  365. */
  366.     prt->tcpout.t.ack = longswap(prt->in.nxt);
  367. /*
  368. *  any more flags should be set?
  369. */
  370.     if (wind->push) {                    /* is push indicator on? */
  371.         prt->tcpout.t.flags |= TPUSH;
  372.         wind->push = 0;
  373.     }
  374.  
  375.     if ((bites <= 0) || prt->state != SEST) {    /* if no data to send . . . */
  376.         tcpsend(prt,0);                /* just a retransmission or ACK */
  377.         return(0);
  378.     }
  379.  
  380. /*
  381. *  we have data to send, get the correct sequence #'s 
  382. */
  383.     saveseq = wind->nxt;
  384.  
  385.     whereb = wind->where;
  386.     endb = wind->endbuf;
  387.     baseb = wind->base;
  388. /*
  389. *  in a loop, transmit the entire queue of data 
  390. */
  391.     for (i=0 ; i < bites; i += prt->sendsize) {
  392.         n = prt->sendsize;
  393.         if (i + n > bites)
  394.             n = bites - i;
  395.  
  396.         j = endb - baseb;
  397.  
  398.         if (j < n) {
  399.             memmove((void *) prt->tcpout.x.data,baseb,j);            /* BYU LSC */
  400.             memmove((char *) (prt->tcpout.x.data+j),whereb,n-j);    /* BYU LSC */
  401.             baseb = whereb + n-j;
  402.         }
  403.         else {
  404.             memmove((void *) prt->tcpout.x.data, baseb, n);            /* BYU LSC */
  405.             baseb += n;
  406.         }
  407.  
  408.         tcpsend(prt,n);                        /* send it */
  409.         wind->nxt += n;
  410.     }
  411.  
  412.     wind->nxt = saveseq;                    /* get back first seq # */
  413.  
  414.     return(0);
  415. } /* transq */
  416.  
  417. /************************************************************************/
  418. /*  netsleep
  419. *      sleep, while demuxing packets, so we don't miss anything
  420. *
  421. */
  422. int netsleep
  423.   (
  424.     int n
  425.   )
  426.     {
  427.     int i,nmux,redir;
  428.     int32 t,gt,start;
  429.     struct port *p;
  430.     uint8 *pc;
  431.  
  432.     redir = 0;
  433.     start = time(NULL);
  434.  
  435.     if (n)
  436.         t = start + n*TICKSPERSEC;
  437.     else
  438.         t = start;
  439.  
  440.     do {
  441.         nmux = demux(1);                /* demux all packets */
  442.  
  443. /*
  444. *  if there were packets in the incoming packet buffer, then more might
  445. *  have arrived while we were processing them.  This gives absolute priority
  446. *  to packets coming in from the network.
  447. */
  448.         if (nmux)
  449.             continue;
  450.  
  451.         if (IREDIR == netgetevent(ICMPCLASS,&i,&i))
  452.             redir = 1;
  453. /*
  454. *  Check each port to see if action is necessary.
  455. *  This now sends all Ack packets, due to p->lasttime being set to 0L.
  456. *  Waiting for nmux == 0 for sending ACKs makes sure that the network
  457. *  has a much higher priority and reduces the number of unnecessary ACKs.
  458. */
  459.         gt = time(NULL);
  460.  
  461.         for (i=0; i < NPORTS; i++) {
  462.             p = portlist[i];
  463.  
  464.             if ((p->type == 1) && !slip_connection)            /* BYU 2.4.15 */
  465.                 continue;                                    /* BYU 2.4.15 */
  466.  
  467.             if ((p != NULL) && (p->state > SLISTEN)) {
  468.  
  469.                 if (!p->out.lasttime)
  470.                     transq(p);                /* takes care of all ACKs */
  471.  
  472.                 else if ((p->out.contain > 0) || (p->state > SEST)) {
  473. /*
  474. *  if a retransmission timeout occurs, exponential back-off.
  475. *  This number returns toward the correct value by the RTT measurement
  476. *  code in ackcheck.
  477. *
  478. *  fix: 5/12/88, if timer was at MAXRTO, transq didn't get hit - TK
  479. */
  480.                     if ((p->out.lasttime + p->rto < gt)) {
  481.                         if (p->rto < MAXRTO) 
  482.                             p->rto <<= 1;        /* double it */
  483.                         transq(p);
  484.                     }
  485.                 }
  486.  
  487.                 if ((p->out.lasttime + POKEINTERVAL < gt) && 
  488.                     (p->state == SEST))
  489.                     transq(p);
  490. /*
  491. *  check to see if ICMP redirection occurred and needs servicing.
  492. *  If it needs servicing, try to get the new hardware address for the new 
  493. *  gateway.  If an arp was sent during getdlayer, we assume another ICMP
  494. *  redirect will occur, this routine will reactivate, and then the hardware
  495. *  address will be available in the cache.
  496. */
  497.                 if (redir && comparen(p->tcpout.i.ipdest,nnicmpsave,4)) {
  498.                     pc = getdlayer(nnicmpnew);
  499.                     if (pc != NULL)
  500.                         memmove((void *) p->tcpout.d.dest,pc,DADDLEN);        /* BYU LSC */
  501.                 }
  502.             }
  503.         }
  504.         redir = 0;                /* reset flag for next demux */
  505.  
  506.     } while ((t > time(NULL))         /* done yet? */
  507.         && (time(NULL) >= start));  /* allow for wraparound of timer */
  508.  
  509.  
  510.     return(nmux);                /* will demux once, even for sleep(0) */
  511.  
  512. } /* netsleep */
  513.  
  514. #define ERROR_RESOURCE_ID 23237        /* BYU 2.4.16 */
  515. #define ERROR_RESOURCE_COUNT 52        /* BYU 2.4.16 */
  516.  
  517. #if 0                                /* BYU 2.4.16 */
  518. /************************************************************************/
  519. /*  neterrstring
  520. *   returns the string associated with a particular error number
  521. *
  522. *   error number is formatted %4d at the beginning of the string
  523. */
  524. static char *errs[] = {"   0",
  525.             " 100 ...",            /* BYU 2.4.16 - strings moved to resource # 23237 */
  526.                         ""};
  527. #endif                            /* BYU 2.4.16 */
  528.  
  529. static char errspace[80];        /* room for user-defined errors */
  530.  
  531. char *neterrstring(errno)
  532.     int errno;
  533.     {
  534.     int i;
  535.     char s[10];
  536.     Str255 ErrorString;                                    /* BYU 2.4.16 */
  537.  
  538.     if (errno < 0) 
  539.         return(errspace);
  540.  
  541.     sprintf(s,"%4d",errno);
  542.  
  543. #if 1                                                    /* BYU 2.4.16 */
  544.     for (i=1; i<=ERROR_RESOURCE_COUNT; i++) {            /* BYU 2.4.16 */
  545.         GetIndString(ErrorString,ERROR_RESOURCE_ID,i);    /* BYU 2.4.16 */
  546.         p2cstr(ErrorString);                            /* BYU 2.4.16 */
  547.         if (!strncmp((char *) ErrorString,s,4))            /* BYU 2.4.16 */
  548.             return((char *) ErrorString + 5);            /* BYU 2.4.16 - pointer to error message  */
  549.     }                                                    /* BYU 2.4.16 */
  550.  
  551.     GetIndString(ErrorString,ERROR_RESOURCE_ID,1);        /* BYU 2.4.16 */
  552.     return((char *) ErrorString+5);                        /* BYU 2.4.16 - pointer to error message  */
  553. #else                                                    /* BYU 2.4.16 */
  554.     i = 0;
  555.     do {
  556.         if (!strncmp(errs[i],s,4))
  557.             return(errs[i]+5);            /* pointer to error message  */
  558.         i++;
  559.  
  560.     } while (*errs[i] || i > 100);            /* until NULL found */
  561.  
  562.     return(errs[0]+5);                    /* error unknown */
  563. #endif                                        /* BYU 2.4.16 */
  564. }
  565.  
  566.